home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / sdk / vfw11.win / vfwdk / icsample.c_ / icsample.bin
Encoding:
Text File  |  1993-11-19  |  50.7 KB  |  1,723 lines

  1. /****************************************************************************
  2.  *
  3.  *   icsample.c
  4.  * 
  5.  *   ICSAMPLE is a sample installable compressor for Video for Windows.
  6.  ***************************************************************************/
  7. /**************************************************************************
  8.  *
  9.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  10.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  11.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  12.  *  PURPOSE.
  13.  *
  14.  *  Copyright (c) 1992, 1993  Microsoft Corporation.  All Rights Reserved.
  15.  * 
  16.  **************************************************************************/
  17.  
  18. #include <windows.h>
  19. #include <mmsystem.h>
  20. #include <compddk.h>
  21.  
  22. #include "icsample.h"
  23.  
  24. /*****************************************************************************
  25.  *
  26.  * Sample video compressor. This code demonstrates how to implement an
  27.  * installable compressor.
  28.  *
  29.  * The alogorithm we use is very simple:
  30.  * (1)  Keep one out of every 'n' pixels where 'n' is configurable.
  31.  *      Compression is done on a scan-line basis.
  32.  *
  33.  * (2)  For true-color images (16 or 24 bits) give the option of dropping
  34.  *      some of the lower bits.
  35.  *
  36.  ****************************************************************************/
  37.  
  38. typedef BYTE _huge  *HPBYTE ;
  39. typedef WORD _huge  *HPWORD ;
  40. typedef DWORD _huge *HPDWORD ;
  41.  
  42. #define MODNAME         "ICSAMPLE"
  43.  
  44. char    szDescription[] = "Microsoft Sample Compressor";
  45. char    szName[]        = "MS-Samp";
  46. #define FOURCC_SAMP     mmioFOURCC('S','A','M','P')
  47. #define TWOCC_SAMP      aviTWOCC('d', 'c')
  48. #define BI_SAMP         mmioFOURCC('S','m','p','1')
  49. #define VERSION_SAMP    0x00010000      // 1.00
  50.  
  51. extern HANDLE ghModule ;
  52.  
  53. /*****************************************************************************
  54.  *
  55.  * DefaultState holds the compression handler.
  56.  *
  57.  ****************************************************************************/
  58.  
  59. ICSTATE DefaultState = {FOURCC_SAMP,2,0};
  60.  
  61. /*****************************************************************************
  62.  *
  63.  * DefaultDecompressFmt are the default options that will be used if the user
  64.  * compresses an image without configuring us at all first. In the case of
  65.  * the sample compressor, it is the pixel keep ratio.
  66.  *
  67.  ****************************************************************************/
  68. BOOL FAR PASCAL _loadds ConfigureDlgProc(HWND hdlg, short msg, WORD wParam, LONG lParam);
  69.  
  70. /*****************************************************************************
  71.  *
  72.  * Various macros that are useful when dealing with bitmaps.
  73.  *
  74.  ****************************************************************************/
  75.  
  76. #define ALIGNULONG(i)     (((i)+3)&(0xFFFFFFFC))          /* ULONG aligned ! */
  77. #define WIDTHBYTES(i)     ((unsigned)(((i)+31)&(~31))/8)  /* ULONG aligned ! */
  78. #define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  79.  
  80. /*****************************************************************************
  81.  *
  82.  * Function for buffering bits
  83.  *
  84.  ****************************************************************************/
  85.  
  86. typedef struct tagBitBuffer
  87. {
  88.     HPWORD          lpwBuffer ;
  89.     DWORD           dwStored ;
  90.     WORD            wMask ;
  91.     WORD            wFile ;
  92. } BITBUFFER, FAR *LPBITBUFFER ;
  93.  
  94. #define MAX_MASK    (0x8000L)
  95.  
  96. void InitBitBuffer( LPBITBUFFER lpbb,void _huge *lpwBuffer )
  97. {
  98.     /*
  99.     ** Same code is valid for both input and output
  100.     */
  101.     lpbb->lpwBuffer = lpwBuffer ;
  102.     lpbb->dwStored = 0 ;
  103.     lpbb->wMask = MAX_MASK ;
  104.     lpbb->wFile = 0 ;
  105. }
  106.  
  107. void OutputBits( LPBITBUFFER lpbb, WORD wBits, WORD wCount )
  108. {
  109.     WORD    wMask ;
  110.  
  111.     wMask = 1 << (wCount-1) ;
  112.     while (wMask)
  113.     {
  114.         if (wMask&wBits)
  115.             lpbb->wFile |= lpbb->wMask ;
  116.         lpbb->wMask >>= 1 ;
  117.         if ( !lpbb->wMask )
  118.         {
  119.             *lpbb->lpwBuffer++ = lpbb->wFile ;
  120.             lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  121.             lpbb->wFile = 0 ;
  122.             lpbb->wMask = MAX_MASK ;
  123.         }
  124.         wMask >>= 1 ;
  125.     }
  126. }
  127.  
  128. void OutputBitsFlush( LPBITBUFFER lpbb )
  129. {
  130.     if (lpbb->wMask != MAX_MASK)
  131.     {
  132.         *lpbb->lpwBuffer++ = lpbb->wFile ;
  133.         lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  134.     }
  135. }
  136.  
  137. WORD InputBits( LPBITBUFFER lpbb, WORD wCount )
  138. {
  139.     WORD    wMask ;
  140.     WORD    wRet ;
  141.  
  142.     wMask = 1 << (wCount-1) ;
  143.     wRet = 0 ;
  144.     while (wMask)
  145.     {
  146.         if (lpbb->wMask == MAX_MASK)
  147.         {
  148.             lpbb->wFile = *lpbb->lpwBuffer++ ;
  149.             lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
  150.         }
  151.         if (lpbb->wFile&lpbb->wMask)
  152.             wRet |= wMask ;
  153.         wMask >>= 1 ;
  154.         lpbb->wMask >>= 1 ;
  155.         if (!lpbb->wMask)
  156.             lpbb->wMask = MAX_MASK ;
  157.     }
  158.  
  159.     return wRet ;
  160. }
  161.  
  162. /*****************************************************************************
  163.  *
  164.  * getDecompressFmtPtr()
  165.  *
  166.  * This routine returns a pointer to the location of the decompression
  167.  * format relative to the specified bitmapinfo header pointer.
  168.  *
  169.  ****************************************************************************/
  170. LPDECOMP_FMT getDecompressFmtPtr(
  171.     LPBITMAPINFOHEADER lpbiSrc)
  172. {
  173.     LPDECOMP_FMT  lpDecompressFmt;
  174.  
  175.     lpbiSrc++;
  176.     lpDecompressFmt = (LPDECOMP_FMT)lpbiSrc;
  177.     lpDecompressFmt->dwSize = sizeof(DECOMPRESS_INFO);
  178.     lpbiSrc--;
  179.     return lpDecompressFmt;
  180. }
  181.  
  182.  
  183.  
  184. /*****************************************************************************
  185.  *
  186.  * MyCompress8
  187.  *
  188.  * This routine handles the actual compression of the bitmap. Note:
  189.  *
  190.  * 1) The use of _huge pointers as the bitmaps are likely to exceed 64k.
  191.  *
  192.  * 2) We must set the biCompression field of the output header.
  193.  *
  194.  * 3) We must set the biSizeImage field of the output header.
  195.  *
  196.  * 4) Uncompressed bitmap scan lines are padded out to the next DWORD
  197.  *    boundry.
  198.  *
  199.  ****************************************************************************/
  200. DWORD NEAR PASCAL MyCompress8(
  201.     INSTINFO * pinst,
  202.     LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
  203.     LPBITMAPINFOHEADER lpbiOutput,HPBYTE hpOutput)
  204. {
  205.     WORD    wRealLineSize ;
  206.     WORD    wLinePad ;
  207.     WORD    wWidth = (WORD)lpbiInput->biWidth ;
  208.     WORD    wHeight = (WORD)lpbiInput->biHeight ;
  209.     WORD    x,y ;
  210.     WORD    wPixRatio = pinst->CurrentState.dInfo.wPixelKeepRatio;
  211.     LPDECOMP_FMT  lpDecompressFmt;
  212.  
  213.     DPF("Compress8()");
  214.  
  215.     //
  216.     // Initialize the pointer to the decompression format which
  217.     // is located after the BITMAPINFOHEADER.
  218.     //
  219.     lpDecompressFmt = getDecompressFmtPtr(lpbiOutput);
  220.  
  221.     //
  222.     // Set the decompression format in the output header.  Colors to 
  223.     // drop is not used in the decompression of 8 bit, so set it to 0.
  224.     //
  225.     lpDecompressFmt->dInfo.wPixelKeepRatio = wPixRatio;
  226.     lpDecompressFmt->dInfo.wColorBitsToDrop = 0;
  227.     
  228.     //
  229.     // Set the bit count, the compression, and the size of the compressed
  230.     // data.  
  231.     //
  232.     lpbiOutput->biBitCount    = 8;
  233.     lpbiOutput->biCompression = BI_SAMP;
  234.     lpbiOutput->biSizeImage   = sizeof(WORD)+((wWidth+wPixRatio-1)/wPixRatio)*(DWORD)wHeight;
  235.     lpbiOutput->biSize        = sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT);
  236.  
  237.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth) ;
  238.     wLinePad      = wRealLineSize-wWidth ;
  239.  
  240.     for (y=0; y<wHeight; y++ )
  241.     {
  242.     //
  243.     // Report status every STATUS_EVERY lines.  This is done by
  244.     // invoking the Status function that is set in response to the 
  245.     // ICM_SET_STATUS_PROC message.
  246.     //
  247.         if (pinst->Status && ((y % STATUS_EVERY) == 0)) {
  248.         if (pinst->Status(pinst->lParam,
  249.                   ICSTATUS_STATUS,
  250.                   (y * 100) / wHeight) != 0)
  251.         return (DWORD) ICERR_ABORT;
  252.     }
  253.  
  254.         for (x=0; x<wWidth; x += wPixRatio)
  255.         {
  256.             *hpOutput++ = *hpInput ;
  257.             hpInput += min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  258.         }
  259.  
  260.         hpInput += wLinePad ;
  261.     }
  262.  
  263.     return 0;
  264. }
  265.  
  266. /*****************************************************************************
  267.  *
  268.  * 16/24 bit compression. Same thing; we just deal with a 2 or 3 bytes per pixel
  269.  * instead of a byte.
  270.  *
  271.  * Note that 8-bit pixel values are indices into a palette; 16-bit and
  272.  * about are actual color values. In particular, 16-bit values are
  273.  * stored as:
  274.  *
  275.  * +-+-----+-----+-----+
  276.  * | |  R  |  G  |  B  |
  277.  * +-+-----+-----+-----+
  278.  *  1 1   1
  279.  *  5 4   0 9   5 4   0
  280.  *
  281.  * Bit 15 is unused; each of red, green, and blue get 5 bits of color data
  282.  * (0-31).
  283.  *
  284.  * For 24 bit images, each pixel is three bytes long. The bytes hold
  285.  * the blue, green, and red values respectively (NOTE THE ORDER IS
  286.  * OPPOSITE OF RGB!)
  287.  *
  288.  ****************************************************************************/
  289. DWORD NEAR PASCAL MyCompress16(
  290.     INSTINFO * pinst,
  291.     LPBITMAPINFOHEADER lpbiInput, HPWORD hpInput,
  292.     LPBITMAPINFOHEADER lpbiOutput,HPWORD hpOutput)
  293. {
  294.     WORD        wRealLineSize ;
  295.     WORD        wLinePad ;
  296.     WORD        wWidth = (WORD)lpbiInput->biWidth ;
  297.     WORD        wHeight = (WORD)lpbiInput->biHeight ;
  298.     WORD        x,y ;
  299.     WORD        wPixRatio=pinst->CurrentState.dInfo.wPixelKeepRatio;
  300.     WORD        wDropBits=pinst->CurrentState.dInfo.wColorBitsToDrop;
  301.     WORD        wKeepBits;
  302.     WORD        r,g,b ;
  303.     LPDECOMP_FMT lpDecompressFmt;
  304.     BITBUFFER   bb ;
  305.  
  306.     DPF("Compress16()") ;
  307.     
  308.     //
  309.     // Initialize the pointer to the decompression format which
  310.     // is located after the BITMAPINFOHEADER.
  311.     //
  312.     lpDecompressFmt = getDecompressFmtPtr(lpbiOutput);
  313.  
  314.     //
  315.     // Set the decompression format in the output header.  
  316.     //
  317.     lpDecompressFmt->dInfo.wPixelKeepRatio = wPixRatio;
  318.     lpDecompressFmt->dInfo.wColorBitsToDrop = wDropBits;
  319.     wKeepBits = 5 - wDropBits;
  320.  
  321.     //
  322.     // Set the bit count, the compression, and the size of the compressed
  323.     // data.  
  324.     //
  325.     lpbiOutput->biBitCount    = 16;
  326.     lpbiOutput->biCompression = BI_SAMP;
  327.     lpbiOutput->biSizeImage   = sizeof(WORD)+2*((wWidth+wPixRatio-1)/wPixRatio)*(DWORD)wHeight;
  328.     lpbiOutput->biSize        = sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT);
  329.  
  330.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*2) ;
  331.     wLinePad      = wRealLineSize - (wWidth*2) ;
  332.  
  333.     InitBitBuffer( &bb,hpOutput ) ;
  334.     
  335.     for (y=0; y<wHeight; y++ )
  336.     {
  337.     //
  338.     // Report status every STATUS_EVERY lines.  This is done by
  339.     // invoking the Status function that is set in response to the 
  340.     // ICM_SET_STATUS_PROC message.
  341.     //
  342.     if (pinst->Status && ((y % STATUS_EVERY) == 0)) {
  343.         if (pinst->Status(pinst->lParam,
  344.                   ICSTATUS_STATUS,
  345.                   (y * 100) / wHeight) != 0)
  346.         return (DWORD) ICERR_ABORT;
  347.     }
  348.  
  349.         for (x=0; x<wWidth; x += wPixRatio)
  350.         {
  351.             r = ((*hpInput>>10)&0x1F)>>wDropBits ;
  352.             g = ((*hpInput>>5)&0x1F)>>wDropBits ;
  353.             b = (*hpInput&0x1F)>>wDropBits ;
  354.             hpInput += min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  355.  
  356.             OutputBits( &bb, r, wKeepBits ) ;
  357.             OutputBits( &bb, g, wKeepBits ) ;
  358.             OutputBits( &bb, b, wKeepBits ) ; 
  359.         }
  360.  
  361.         hpInput += wLinePad ;
  362.     }
  363.  
  364.     OutputBitsFlush(&bb) ;
  365.  
  366.     lpbiOutput->biSizeImage = bb.dwStored ;
  367.  
  368.     return 0;
  369. }   
  370.     
  371. DWORD NEAR PASCAL MyCompress24(
  372.     INSTINFO * pinst,
  373.     LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
  374.     LPBITMAPINFOHEADER lpbiOutput,HPBYTE hpOutput)
  375. {
  376.     WORD        wRealLineSize ;
  377.     WORD        wLinePad ;
  378.     WORD        wWidth = (WORD)lpbiInput->biWidth ;
  379.     WORD        wHeight = (WORD)lpbiInput->biHeight ;
  380.     WORD        x,y ;
  381.     WORD        wPixRatio=pinst->CurrentState.dInfo.wPixelKeepRatio;
  382.     WORD        wDropBits=pinst->CurrentState.dInfo.wColorBitsToDrop;
  383.     WORD        wKeepBits;
  384.     WORD        r,g,b ;
  385.     LPDECOMP_FMT  lpDecompressFmt;
  386.     BITBUFFER   bb ;
  387.  
  388.     DPF("Compress24()") ;
  389.     
  390.     //
  391.     // Initialize the pointer to the decompression format which
  392.     // is located after the BITMAPINFOHEADER.
  393.     //
  394.     lpDecompressFmt = getDecompressFmtPtr(lpbiOutput);
  395.  
  396.     //
  397.     // Set the decompression format in the output header.  
  398.     //
  399.     lpDecompressFmt->dInfo.wPixelKeepRatio = wPixRatio;
  400.     lpDecompressFmt->dInfo.wColorBitsToDrop = wDropBits;
  401.     wKeepBits = 8 - wDropBits;
  402.  
  403.     //
  404.     // Set the bit count and the compression.
  405.     //
  406.     lpbiOutput->biBitCount    = 24 ;
  407.     lpbiOutput->biCompression = BI_SAMP;
  408.     lpbiOutput->biSize        = sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT);
  409.  
  410.     wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*3) ;
  411.     wLinePad      = wRealLineSize - (wWidth * 3);
  412.  
  413.     InitBitBuffer( &bb,hpOutput ) ;
  414.     
  415.     for (y=0; y<wHeight; y++ )
  416.     {
  417.     //
  418.     // Report status every STATUS_EVERY lines.  This is done by
  419.     // invoking the Status function that is set in response to the 
  420.     // ICM_SET_STATUS_PROC message.
  421.     //
  422.     if (pinst->Status && ((y % STATUS_EVERY) == 0)) {
  423.         if (pinst->Status(pinst->lParam,
  424.                   ICSTATUS_STATUS,
  425.                   (y * 100) / wHeight) != 0)
  426.         return (DWORD) ICERR_ABORT;
  427.     }
  428.  
  429.         for (x=0; x<wWidth; x += wPixRatio)
  430.         {
  431.             b = (hpInput[0])>>wDropBits ;
  432.             g = (hpInput[1])>>wDropBits ;
  433.             r = (hpInput[2])>>wDropBits ;
  434.             hpInput += 3 * min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
  435.  
  436.             OutputBits( &bb, r, wKeepBits ) ;
  437.             OutputBits( &bb, g, wKeepBits ) ;
  438.             OutputBits( &bb, b, wKeepBits ) ; 
  439.         }
  440.  
  441.         ((HPBYTE)hpInput) += wLinePad ;
  442.     }
  443.     OutputBitsFlush(&bb) ;
  444.  
  445.     lpbiOutput->biSizeImage = bb.dwStored ;
  446.  
  447.     return 0;
  448. }
  449.  
  450. /**************************************************************************
  451. compute a pointer into a DIB handling correctly "upside" down DIBs
  452. ***************************************************************************/
  453.  
  454. static LPVOID DibXY(LPBITMAPINFOHEADER lpbi, LPVOID lpBits, LONG x, LONG y, int FAR *pWidthBytes)
  455. {
  456.     int WidthBytes;
  457.  
  458.     if (x > 0)
  459.         ((BYTE FAR *)lpBits) += ((int)x * (int)lpbi->biBitCount) >> 3;
  460.  
  461.     WidthBytes = (((((int)lpbi->biWidth * (int)lpbi->biBitCount) >> 3) + 3)&~3);
  462.  
  463.     if (lpbi->biHeight < 0)
  464.     {
  465.         ((BYTE _huge *)lpBits) += (long)(lpbi->biSizeImage - WidthBytes);
  466.         WidthBytes = -WidthBytes;
  467.     }
  468.  
  469.     if (y > 0)
  470.         ((BYTE _huge *)lpBits) += ((long)y * WidthBytes);
  471.  
  472.     if (pWidthBytes)
  473.         *pWidthBytes = WidthBytes;
  474.  
  475.     return lpBits;
  476. }
  477.  
  478. #pragma optimize("", off)           //huge pointer math geting hosed
  479.     
  480. /*****************************************************************************
  481.  *
  482.  * MyDecompress
  483.  *
  484.  * This function is the inverse of MyCompress and follows the same caveats.
  485.  *
  486.  * We shouldn't depend on the state to accurately tell us how to
  487.  * decompress; this info needs to come totally from the compressed data!
  488.  *
  489.  ****************************************************************************/
  490. void NEAR PASCAL MyDecompress8(
  491.     INSTINFO * pinst,
  492.     LPBITMAPINFOHEADER lpbiInput,  HPBYTE hpInput,
  493.     LPBITMAPINFOHEADER lpbiOutput, HPBYTE hpOutput, int x, int y)
  494. {
  495.     int         xrun ;
  496.     int         wRealLineSize ;
  497.     long        wLinePad ;
  498.     LPDECOMP_FMT lpDecompressFmt;
  499.     int         wWidth  = (int)lpbiInput->biWidth;
  500.     int         wHeight = (int)lpbiInput->biHeight;
  501.  
  502.     hpOutput = DibXY(lpbiOutput, hpOutput, x, y, &wRealLineSize);
  503.     wLinePad = wRealLineSize - wWidth;
  504.  
  505.     //
  506.     // Initialize the pointer to the decompression format which
  507.     // follows the bitmapinfo header.
  508.     //
  509.     lpDecompressFmt = getDecompressFmtPtr(lpbiInput);
  510.     for (y=0; y < wHeight; y++)
  511.     {
  512.         for (x=0; x<wWidth; )
  513.         {
  514.             xrun = min(wWidth-x,(int)lpDecompressFmt->dInfo.wPixelKeepRatio) ;
  515.             x += xrun ;
  516.             while (xrun--)
  517.                 *hpOutput++ = *hpInput ;
  518.  
  519.             hpInput++ ;
  520.         }
  521.  
  522.         hpOutput += wLinePad ;
  523.     }
  524. }
  525.  
  526. void NEAR PASCAL MyDecompress16(
  527.     INSTINFO * pinst,
  528.     LPBITMAPINFOHEADER lpbiInput,  HPWORD hpInput,
  529.     LPBITMAPINFOHEADER lpbiOutput, HPWORD hpOutput, int x, int y)
  530. {
  531.     int         xrun ;
  532.     int         wRealLineSize ;
  533.     long        wLinePad ;
  534.     LPDECOMP_FMT lpDecompressFmt;
  535.     int         wWidth  = (int)lpbiInput->biWidth ;
  536.     int         wHeight = (int)lpbiInput->biHeight ;
  537.     UINT        wDropBits ;
  538.     UINT        wKeepBits ;
  539.     UINT        r,g,b,color ;
  540.     BITBUFFER   bb ;
  541.  
  542.     hpOutput = DibXY(lpbiOutput, hpOutput, x, y, &wRealLineSize);
  543.     wLinePad = wRealLineSize - (wWidth*2) ;
  544.  
  545.     //
  546.     // Initialize the pointer to the decompression format which
  547.     // follows the bitmapinfo header.
  548.     //
  549.     lpDecompressFmt = getDecompressFmtPtr(lpbiInput);
  550.  
  551.     wDropBits = lpDecompressFmt->dInfo.wColorBitsToDrop ;
  552.     wKeepBits = 5 - wDropBits ;
  553.  
  554.     InitBitBuffer( &bb, hpInput ) ;
  555.  
  556.     for (y=0; y < wHeight; y++)
  557.     {
  558.         for (x=0; x<wWidth; )
  559.         {
  560.             r = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  561.             g = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  562.             b = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  563.  
  564.             color = (r << 10) | (g << 5) | b ;
  565.             
  566.             xrun = min(wWidth-x,(int)lpDecompressFmt->dInfo.wPixelKeepRatio) ;
  567.             x += xrun ;
  568.             while (xrun--)
  569.                 *hpOutput++ = color ;
  570.         }
  571.  
  572.         ((BYTE _huge *)hpOutput) += wLinePad ;
  573.     }
  574. }
  575.  
  576. void NEAR PASCAL MyDecompress24(
  577.     INSTINFO * pinst,
  578.     LPBITMAPINFOHEADER lpbiInput,  HPBYTE hpInput,
  579.     LPBITMAPINFOHEADER lpbiOutput, HPBYTE hpOutput, int x, int y)
  580. {
  581.     int         xrun ;
  582.     int         wRealLineSize ;
  583.     long        wLinePad ;
  584.     LPDECOMP_FMT lpDecompressFmt;
  585.     int         wWidth  = (int)lpbiInput->biWidth ;
  586.     int         wHeight = (int)lpbiInput->biHeight ;
  587.     WORD        wDropBits ;  
  588.     WORD        wKeepBits ;
  589.     WORD        r,g,b ;
  590.     BITBUFFER   bb ;
  591.  
  592.     hpOutput = DibXY(lpbiOutput, hpOutput, x, y, &wRealLineSize);
  593.     wLinePad = wRealLineSize - (wWidth*3);
  594.  
  595.     //
  596.     // Initialize the pointer to the decompression format which
  597.     // follows the bitmapinfo header.
  598.     //
  599.     lpDecompressFmt = getDecompressFmtPtr(lpbiInput);
  600.  
  601.     wDropBits = lpDecompressFmt->dInfo.wColorBitsToDrop ;
  602.     wKeepBits = 8 - wDropBits ;
  603.  
  604.     InitBitBuffer( &bb, hpInput ) ;
  605.  
  606.     for (y=0; y < wHeight; y++)
  607.     {
  608.         for (x=0; x<wWidth; )
  609.         {
  610.             r = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  611.             g = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  612.             b = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
  613.  
  614.             xrun = min(wWidth-x,(int)lpDecompressFmt->dInfo.wPixelKeepRatio) ;
  615.             x += xrun ;
  616.             while (xrun--)
  617.             {
  618.                 *hpOutput++ = (BYTE)b ;
  619.                 *hpOutput++ = (BYTE)g ;
  620.                 *hpOutput++ = (BYTE)r ;
  621.             }
  622.         }
  623.  
  624.         hpOutput += wLinePad ;
  625.     }
  626. }
  627.  
  628. #pragma optimize("", on)           //huge pointer math geting hosed
  629.  
  630. /*****************************************************************************
  631.  *
  632.  * Load() is called from the DRV_LOAD message.
  633.  *
  634.  * Tasks such as allocating global memory that is non-instance specific
  635.  * or initializing coprocessor hardware may be performed here.
  636.  *
  637.  * Our simple case needs none of this.
  638.  *
  639.  ****************************************************************************/
  640. BOOL NEAR PASCAL Load(void)
  641. {
  642.     DPF("Load()");
  643.     return TRUE;
  644. }
  645.  
  646. /*****************************************************************************
  647.  *
  648.  * Free() is called from the DRV_FREE message.
  649.  *
  650.  * It should totally reverse the effects of Load() in preparation for
  651.  * the DRV being removed from memory.
  652.  *
  653.  ****************************************************************************/
  654. void NEAR PASCAL Free()
  655. {
  656.     DPF("Free()");
  657. }
  658.  
  659. /*****************************************************************************
  660.  *
  661.  * Open() is called from the ICM_OPEN message
  662.  *
  663.  * This message will be sent for a particular compress/decompress session.
  664.  * Our code must verify that we are indeed being called as a video
  665.  * compressor and create/initialize a state structure. The ICM will
  666.  * give us back the pointer to that structure on every message dealing
  667.  * with this session.
  668.  *
  669.  ****************************************************************************/
  670. INSTINFO * NEAR PASCAL Open(ICOPEN FAR * icinfo)
  671. {
  672.     INSTINFO *  pinst;
  673.  
  674.     DPF("Open('%4.4ls', '%4.4ls')", (LPSTR)&icinfo->fccType, (LPSTR)&icinfo->fccHandler);
  675.  
  676.     //
  677.     // refuse to open if we are not being opened as a Video compressor
  678.     //
  679.     if (icinfo->fccType != ICTYPE_VIDEO)
  680.         return NULL;
  681.  
  682.     pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
  683.  
  684.     if (!pinst)
  685.     {
  686.         icinfo->dwError = ICERR_MEMORY;
  687.         return NULL;
  688.     }
  689.  
  690.     //
  691.     // init structure
  692.     //
  693.     pinst->fccType = ICTYPE_VIDEO;
  694.     pinst->dwFlags = icinfo->dwFlags;
  695.     pinst->fCompress   = FALSE;
  696.     pinst->fDecompress = FALSE;
  697.     pinst->fDrawBegun  = FALSE;
  698.  
  699.     //
  700.     // set the default state.
  701.     //
  702.     SetState(pinst, NULL, 0);
  703.  
  704.     //
  705.     // return success.
  706.     //
  707.     icinfo->dwError = ICERR_OK;
  708.  
  709.     return pinst;
  710. }
  711.  
  712. /*****************************************************************************
  713.  *
  714.  * Close() is called on the ICM_CLOSE message.
  715.  *
  716.  * This message is the complement to ICM_OPEN and marks the end
  717.  * of a compress/decompress session. We kill any in-progress operations
  718.  * (although this shouldn't be needed) and free our instance structure.
  719.  *
  720.  ****************************************************************************/
  721. DWORD NEAR PASCAL Close(INSTINFO * pinst)
  722. {
  723.     DPF("Close()");
  724.  
  725.     if (pinst->fCompress)
  726.         CompressEnd(pinst);
  727.  
  728.     if (pinst->fDecompress)
  729.         DecompressEnd(pinst);
  730.  
  731.     if (pinst->fDrawBegun)
  732.         DrawEnd(pinst);
  733.    
  734.     LocalFree((HLOCAL)pinst);
  735.     
  736.     return 1;
  737. }
  738.  
  739. /*****************************************************************************
  740.  *
  741.  * QueryAbout() and About() handle the ICM_ABOUT message.
  742.  *
  743.  * QueryAbout() returns TRUE to indicate we support an about box.
  744.  * About() displays the box.
  745.  *
  746.  ****************************************************************************/
  747. BOOL NEAR PASCAL QueryAbout(INSTINFO * pinst)
  748. {
  749.     DPF("QueryAbout()");
  750.  
  751.     return TRUE;
  752. }
  753.  
  754. DWORD NEAR PASCAL About(INSTINFO * pinst, HWND hwnd)
  755. {
  756.     DPF("About()");
  757.     MessageBox(hwnd,szDescription,szName,MB_OK|MB_ICONINFORMATION);
  758.     return ICERR_OK;
  759. }
  760.  
  761. /*****************************************************************************
  762.  *
  763.  * QueryConfigure() and Configure() implement the ICM_CONFIGURE message.
  764.  *
  765.  * These functions put up a dialog that allows the user, if he so
  766.  * chooses, to modify the configuration portion of our state info.
  767.  * 
  768.  ****************************************************************************/
  769. BOOL NEAR PASCAL QueryConfigure(INSTINFO * pinst)
  770. {
  771.     DPF("QueryConfigure()");
  772.     return TRUE;
  773. }
  774.  
  775. DWORD NEAR PASCAL Configure(INSTINFO * pinst, HWND hwnd)
  776. {
  777.     DPF("Configure()");
  778.     return DialogBoxParam(ghModule,"Configure",hwnd,ConfigureDlgProc, (LONG)(WORD)pinst);
  779. }
  780.  
  781. /*****************************************************************************
  782.  *
  783.  * GetState() implements the ICM_GETSTATE message.
  784.  * 
  785.  * We copy our configuration information and return how many bytes it took.
  786.  *
  787.  ****************************************************************************/
  788. DWORD NEAR PASCAL GetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
  789. {
  790.     DPF("GetState(%08lX, %ld)", pv, dwSize);
  791.  
  792.     if (pv == NULL || dwSize == 0)
  793.         return sizeof(ICSTATE);
  794.  
  795.     if (dwSize < sizeof(ICSTATE))
  796.         return 0;
  797.  
  798.     *((ICSTATE FAR *)pv) = pinst->CurrentState;
  799.  
  800.     // return number of bytes copied
  801.     return sizeof(ICSTATE);
  802. }
  803.  
  804. /*****************************************************************************
  805.  *
  806.  * SetState() implements the ICM_SETSTATE message.
  807.  *
  808.  * The ICM is giving us configuration information saved by GetState()
  809.  * earlier.
  810.  *
  811.  ****************************************************************************/
  812. DWORD NEAR PASCAL SetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
  813. {
  814.     DPF("SetState(%08lX, %ld)", pv, dwSize);
  815.  
  816.     //
  817.     //  make sure we created this state information.
  818.     //
  819.     if (pv && ((ICSTATE FAR *)pv)->fccHandler != FOURCC_SAMP)
  820.         return 0;
  821.  
  822.     if (pv == NULL)
  823.         pinst->CurrentState = DefaultState;
  824.     else if (dwSize >= sizeof(ICSTATE))
  825.         pinst->CurrentState = *((ICSTATE FAR *)pv);
  826.     else
  827.         return 0;
  828.  
  829.     // return number of bytes copied
  830.     return sizeof(ICSTATE);
  831. }
  832.  
  833. /*****************************************************************************
  834.  *
  835.  * GetInfo() implements the ICM_GETINFO message
  836.  *
  837.  * We just fill in the structure to tell the ICM what we can do. The flags
  838.  * (none of which this sample supports) mean the following :
  839.  *
  840.  * VIDCF_QUALITY - we support the quality variable. This means we look at
  841.  *                 dwQuality in the ICINFO structure when compressing and
  842.  *                 make a concious decision to trade quality for space.
  843.  *                 (higher values of dwQuality mean quality is more
  844.  *                 important). dwQuality is set by the ICM.
  845.  *
  846.  * VIDCF_TEMPORAL - We do interframe compression. In this algorithm, not
  847.  *                  every frame is a "key frame"; some frames depend on
  848.  *                  other frames to be generated. An example of this might
  849.  *                  be to store frame buffer differences until the
  850.  *                  differences are big enough to no longer make this
  851.  *                  worthwhile, then storing another complete frame and
  852.  *                  starting over. In this case, the complete frames that
  853.  *                  are stored are key frames and should be flagged as
  854.  *                  such.
  855.  *
  856.  * VIDCF_DRAW -     We will draw the decompressed image on our own. This is
  857.  *                  useful if the decompression is assisted by the video
  858.  *                  hardware.
  859.  *
  860.  ****************************************************************************/
  861. DWORD NEAR PASCAL GetInfo(INSTINFO * pinst, ICINFO FAR *icinfo, DWORD dwSize)
  862. {
  863.     DPF("GetInfo()");
  864.  
  865.     if (icinfo == NULL)
  866.         return sizeof(ICINFO);
  867.  
  868.     if (dwSize < sizeof(ICINFO))
  869.         return 0;
  870.  
  871.     icinfo->dwSize            = sizeof(ICINFO);
  872.     icinfo->fccType           = ICTYPE_VIDEO;
  873.     icinfo->fccHandler        = FOURCC_SAMP;
  874.     icinfo->dwFlags           = 0;
  875.  
  876.                 //              VIDCF_QUALITY    // supports quality
  877.                 //              VIDCF_TEMPORAL   // supports inter-frame
  878.                 //              VIDCF_DRAW       // supports drawing
  879.  
  880.     icinfo->dwVersion         = VERSION_SAMP;
  881.     icinfo->dwVersionICM      = ICVERSION;
  882.     lstrcpy(icinfo->szDescription, szDescription);
  883.     lstrcpy(icinfo->szName, szName);
  884.  
  885.     return sizeof(ICINFO);
  886. }
  887.  
  888. /*****************************************************************************
  889.  *
  890.  * CompressQuery() handles the ICM_COMPRESSQUERY message
  891.  *
  892.  * This message basically asks, "Can you compress this into this?"
  893.  *
  894.  * We look at the input and output bitmap info headers and determine
  895.  * if we can.
  896.  *
  897.  ****************************************************************************/
  898. LRESULT NEAR PASCAL CompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  899. {
  900.     DPF("CompressQuery()");
  901.  
  902.     //
  903.     // determine if the input DIB data is in a format we like.
  904.     //
  905.     if (lpbiIn == NULL ||
  906.         (lpbiIn->biBitCount != 8 && lpbiIn->biBitCount != 16 && lpbiIn->biBitCount != 24) ||
  907.         lpbiIn->biCompression != BI_RGB)
  908.     {
  909.         return ICERR_BADFORMAT;
  910.     }
  911.  
  912.     //
  913.     //  are we being asked to query just the input format?
  914.     //
  915.     if (lpbiOut == NULL)
  916.         return ICERR_OK;
  917.  
  918.     //
  919.     // make sure we can handle the format to compress to also.
  920.     //
  921.     if (lpbiOut->biCompression != BI_SAMP ||    // must be 'Smp1'
  922.         lpbiOut->biBitCount != lpbiIn->biBitCount ||
  923.         lpbiOut->biSize != (sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT)) ||
  924.         lpbiOut->biWidth  != lpbiIn->biWidth || // must be 1:1 (no stretch)
  925.         lpbiOut->biHeight != lpbiIn->biHeight)
  926.     {
  927.         return ICERR_BADFORMAT;
  928.     }
  929.  
  930.     return ICERR_OK;
  931. }
  932.  
  933. /*****************************************************************************
  934.  *
  935.  * CompressGetFormat() implements ICM_GETFORMAT
  936.  *
  937.  * This message asks, "If I gave you this bitmap, how much memory would it
  938.  * be compressed?"
  939.  *
  940.  * If the output bitmap info header is NULL, we just return how big the
  941.  * header would be (header + format information (if any) + palette, actually).  
  942.  * The format is any information that the decompressor might need to 
  943.  * decompress the data.
  944.  *
  945.  * Otherwise, we fill in the header, most importantly the biSizeImage.
  946.  * This field must contain an upper bound on the size of the compressed
  947.  * frame. A value that is too high here will result in inefficient
  948.  * memory allocation at compression time, but will not be reflected
  949.  * to the stored bitmap - the compression algorithm may chop biSizeImage
  950.  * down to the actual amount with no ill effects.
  951.  * 
  952.  ****************************************************************************/
  953. LRESULT NEAR PASCAL CompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  954. {
  955.     DWORD dw;
  956.     LPDECOMP_FMT  lpDecompressFmt;
  957.  
  958.     DPF("CompressGetFormat()");
  959.  
  960.     if (dw = CompressQuery(pinst, lpbiIn, NULL))
  961.         return dw;
  962.  
  963.     //
  964.     // if lpbiOut == NULL then, return the size required to hold a output
  965.     // format.  Remember, if you have decompress format information
  966.     // in the header, then make room for it.    
  967.     //
  968.     if (lpbiOut == NULL)
  969.         return (int)sizeof(BITMAPINFOHEADER) + (int)sizeof(DECOMP_FORMAT) +
  970.                (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
  971.  
  972.     // 
  973.     // First copy the bitmapinfo header.
  974.     //
  975.     hmemcpy(lpbiOut, lpbiIn, (int)lpbiIn->biSize);
  976.     
  977.     //
  978.     // Now copy the decompression formation information.
  979.     //
  980.     lpDecompressFmt = getDecompressFmtPtr(lpbiOut);
  981.     lpDecompressFmt->dInfo.wPixelKeepRatio  = pinst->CurrentState.dInfo.wPixelKeepRatio;
  982.     lpDecompressFmt->dInfo.wColorBitsToDrop = pinst->CurrentState.dInfo.wColorBitsToDrop;
  983.     lpDecompressFmt->dwSize                 = sizeof(DECOMPRESS_INFO);
  984.  
  985.     //
  986.     // Copy the colors. 
  987.     //
  988.     lpbiOut->biSize = sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT);
  989.  
  990.     hmemcpy(
  991.         (LPBYTE)lpbiOut + (int)lpbiOut->biSize,
  992.         (LPBYTE)lpbiIn + (int)lpbiIn->biSize,
  993.         (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  994.  
  995.     lpbiOut->biBitCount    = lpbiIn->biBitCount;
  996.     lpbiOut->biCompression = BI_SAMP;
  997.     lpbiOut->biSizeImage   = CompressGetSize(pinst, lpbiIn, lpbiOut); 
  998.  
  999.     return ICERR_OK;
  1000. }
  1001.  
  1002. /*****************************************************************************
  1003.  *
  1004.  * CompressBegin() implements ICM_COMPRESSBEGIN
  1005.  *
  1006.  * We're about to start compressing, initialize coprocessor, etc.
  1007.  * 
  1008.  ****************************************************************************/
  1009. LRESULT NEAR PASCAL CompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1010. {
  1011.     DWORD dw;
  1012.  
  1013.     DPF("CompressBegin()");
  1014.  
  1015.     if (dw = CompressQuery(pinst, lpbiIn, lpbiOut))
  1016.         return dw;
  1017.  
  1018.     //
  1019.     // initialize for compression, for real....
  1020.     //
  1021.  
  1022.     pinst->fCompress = TRUE;
  1023.  
  1024.     return ICERR_OK;
  1025. }
  1026.  
  1027. /*****************************************************************************
  1028.  *
  1029.  * CompressGetSize() implements ICM_COMPRESS_GET_SIZE
  1030.  *
  1031.  * This function returns how much (upper bound) memory a compressed frame
  1032.  * will take.
  1033.  *
  1034.  ****************************************************************************/
  1035. LRESULT NEAR PASCAL CompressGetSize(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1036. {
  1037.     int dx,dy;
  1038.     WORD    wPixelSize ;
  1039.  
  1040.     DPF("CompressGetSize()");
  1041.  
  1042.     dx = (int)lpbiIn->biWidth;
  1043.     dy = (int)lpbiIn->biHeight;
  1044.  
  1045.     wPixelSize = (lpbiOut->biBitCount+7)/8 ;
  1046.  
  1047.     return wPixelSize*(DWORD)dx*dy ;
  1048. }
  1049.  
  1050. /*****************************************************************************
  1051.  *
  1052.  * Compress() implements ICM_COMPRESS
  1053.  *
  1054.  * Everything is set up; call the actual compression routine.
  1055.  *
  1056.  * Note:
  1057.  *
  1058.  * 1) We set the ckid in icinfo to a two-character code indicating how we
  1059.  *    compressed. This code will be returned to us at decompress time to
  1060.  *    allow us to pick a decompression algorithm to match. This is different
  1061.  *    from icinfo->fccHandler, which tells which driver to use!
  1062.  *
  1063.  * 2) We set the key-frame flag on every frame since we do no
  1064.  *    temporal (inter-frame) compression.
  1065.  *
  1066.  ****************************************************************************/
  1067. LRESULT NEAR PASCAL Compress(INSTINFO * pinst, ICCOMPRESS FAR *icinfo, DWORD dwSize)
  1068. {
  1069.     DWORD dw;
  1070.     BOOL  fBegin;
  1071.  
  1072.     DPF("Compress()");
  1073.  
  1074.     if (dw = CompressQuery(pinst, icinfo->lpbiInput, icinfo->lpbiOutput))
  1075.         return dw;
  1076.  
  1077.     //
  1078.     // check for being called without a BEGIN message
  1079.     //
  1080.     if (!(fBegin = pinst->fCompress))
  1081.     {
  1082.         if (dw = CompressBegin(pinst, icinfo->lpbiInput, icinfo->lpbiOutput))
  1083.             return dw;
  1084.     }
  1085.  
  1086.     if (pinst->Status)
  1087.     //
  1088.     // Start the intervals to the Status procedure.
  1089.     //
  1090.     pinst->Status(pinst->lParam, ICSTATUS_START, 0);
  1091.     
  1092.     /* do the compression */
  1093.     switch(icinfo->lpbiInput->biBitCount)
  1094.     {
  1095.         case 8 :
  1096.             dw = MyCompress8(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  1097.                 icinfo->lpbiOutput, icinfo->lpOutput);
  1098.             break;
  1099.  
  1100.         case 16 :
  1101.             dw = MyCompress16(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  1102.                 icinfo->lpbiOutput, icinfo->lpOutput);
  1103.             break;
  1104.  
  1105.         case 24 :
  1106.             dw = MyCompress24(pinst,icinfo->lpbiInput, icinfo->lpInput, 
  1107.                 icinfo->lpbiOutput, icinfo->lpOutput);
  1108.             break;
  1109.     }
  1110.  
  1111.     //
  1112.     // Stop the intervals to the Status procedure.
  1113.     //
  1114.     if (pinst->Status)
  1115.     pinst->Status(pinst->lParam, ICSTATUS_END, 0);
  1116.     
  1117.     //
  1118.     // return the chunk id
  1119.     //
  1120.     if (icinfo->lpckid)
  1121.         *icinfo->lpckid = TWOCC_SAMP;
  1122.  
  1123.     //
  1124.     // set the AVI index flags,
  1125.     //
  1126.     //    make it a keyframe
  1127.     //
  1128.     if (icinfo->lpdwFlags)
  1129.         *icinfo->lpdwFlags = AVIIF_KEYFRAME;
  1130.  
  1131.     //
  1132.     // do a CompressEnd() for the caller if needed
  1133.     //
  1134.     if (!fBegin)
  1135.     {
  1136.         CompressEnd(pinst);
  1137.     }
  1138.  
  1139.     return dw;
  1140. }
  1141.  
  1142. /*****************************************************************************
  1143.  *
  1144.  * CompressEnd() is called on ICM_COMPRESS_END
  1145.  *
  1146.  * This function is a chance to flush buffers, deinit hardware, etc.
  1147.  * after compressing a single frame.
  1148.  *
  1149.  ****************************************************************************/
  1150. LRESULT NEAR PASCAL CompressEnd(INSTINFO * pinst)
  1151. {
  1152.     DPF("CompressEnd()");
  1153.  
  1154.     if (!pinst->fCompress)
  1155.         return ICERR_ERROR;
  1156.  
  1157.     /* *** your code to clean up here *** */
  1158.  
  1159.     pinst->fCompress = FALSE;
  1160.  
  1161.     return ICERR_OK;
  1162. }
  1163.  
  1164. /*****************************************************************************
  1165.  ****************************************************************************/
  1166. LRESULT NEAR PASCAL DecompressQueryFmt(
  1167.     INSTINFO * pinst,
  1168.     LPBITMAPINFOHEADER lpbiSrc)
  1169. {
  1170.     //
  1171.     // determine if the input DIB data is in a format we like.
  1172.     //
  1173.     if (lpbiSrc == NULL ||
  1174.         !(lpbiSrc->biBitCount == 24 ||
  1175.           lpbiSrc->biBitCount == 16 ||
  1176.           lpbiSrc->biBitCount == 8) ||
  1177.         lpbiSrc->biCompression != BI_SAMP ||
  1178.         lpbiSrc->biSize != (sizeof(BITMAPINFOHEADER) + sizeof(DECOMP_FORMAT))) {
  1179.         return ICERR_BADFORMAT;
  1180.     }
  1181.     return ICERR_OK;
  1182. }
  1183.  
  1184. /*****************************************************************************
  1185.  *
  1186.  * DecompressQuery() implements ICM_DECOMPRESS_QUERY
  1187.  *
  1188.  * See CompressQuery()
  1189.  * 
  1190.  ****************************************************************************/
  1191. LRESULT NEAR PASCAL DecompressQuery(
  1192.     INSTINFO * pinst,
  1193.     DWORD dwFlags,
  1194.     LPBITMAPINFOHEADER lpbiSrc,
  1195.     LPVOID pSrc,
  1196.     int xSrc,
  1197.     int ySrc,
  1198.     int dxSrc,
  1199.     int dySrc,
  1200.     LPBITMAPINFOHEADER lpbiDst,
  1201.     LPVOID pDst,
  1202.     int xDst,
  1203.     int yDst,
  1204.     int dxDst,
  1205.     int dyDst)
  1206. {
  1207.     LRESULT l;
  1208.  
  1209.     DPF("DecompressQuery()");
  1210.  
  1211.     if (l = DecompressQueryFmt(pinst, lpbiSrc))
  1212.         return l;
  1213.  
  1214.     //
  1215.     // allow (-1) as a default width/height
  1216.     //
  1217.     if (dxSrc == -1)
  1218.         dxSrc = (int)lpbiSrc->biWidth;
  1219.  
  1220.     if (dySrc == -1)
  1221.         dySrc = (int)lpbiSrc->biHeight;
  1222.  
  1223.     //
  1224.     //  we cant clip the source.
  1225.     //
  1226.     if (xSrc != 0 || ySrc != 0) 
  1227.         return ICERR_BADPARAM;
  1228.  
  1229.     if (dxSrc != (int)lpbiSrc->biWidth || dySrc != (int)lpbiSrc->biHeight)
  1230.         return ICERR_BADPARAM;
  1231.  
  1232.     //
  1233.     //  are we being asked to query just the input format?
  1234.     //
  1235.     if (lpbiDst == NULL)
  1236.         return ICERR_OK;
  1237.  
  1238.     //
  1239.     // allow (-1) as a default width/height
  1240.     //
  1241.     if (dxDst == -1)
  1242.         dxDst = (int)lpbiDst->biWidth;
  1243.  
  1244.     if (dyDst == -1)
  1245.         dyDst = abs((int)lpbiDst->biHeight);
  1246.  
  1247.     //
  1248.     // make sure we can handle the format to decompress too.
  1249.     //
  1250.     if (lpbiDst->biCompression != BI_RGB ||             // must be full dib
  1251.         lpbiDst->biBitCount != lpbiSrc->biBitCount ||   // must be same bpp
  1252.         lpbiDst->biSize != sizeof(BITMAPINFOHEADER) ||
  1253.         dxSrc != dxDst || dySrc != dyDst)               // must be 1:1 (no stretch)
  1254.     {
  1255.         return ICERR_BADFORMAT;
  1256.     }
  1257.  
  1258.     return ICERR_OK;
  1259. }
  1260.  
  1261. /*****************************************************************************
  1262.  *
  1263.  * DecompressGetFormat() implements ICM_DECOMPRESS_GET_FORMAT
  1264.  *
  1265.  * See CompressGetFormat()
  1266.  *
  1267.  ****************************************************************************/
  1268. LRESULT NEAR PASCAL DecompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1269. {
  1270.     DWORD dw;
  1271.     int dx,dy;
  1272.     WORD    wBytesPerPixel ;
  1273.  
  1274.     DPF("DecompressGetFormat()");
  1275.  
  1276.     if (dw = DecompressQueryFmt(pinst, lpbiIn))
  1277.         return dw;
  1278.  
  1279.     //
  1280.     // if lpbiOut == NULL then, return the size required to hold an output
  1281.     // format.  Remember to copy the bitmapinfo header and the colors,
  1282.     // but not the decompression format which gives the driver information
  1283.     // on how to decompress the data.  
  1284.     //
  1285.     if (lpbiOut == NULL)
  1286.         return (int)sizeof(BITMAPINFOHEADER) + 
  1287.                (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
  1288.  
  1289.     //
  1290.     // First copy the bitmapinfo header, then skip over the decompression
  1291.     // information in the IN buffer, and copy the colors.  The decompression
  1292.     // information is not part of the decompression format.
  1293.     //
  1294.     hmemcpy(lpbiOut, lpbiIn,
  1295.         (int)sizeof(BITMAPINFOHEADER));
  1296.  
  1297.     lpbiOut->biSize        = sizeof(BITMAPINFOHEADER);
  1298.     lpbiOut->biClrUsed     = lpbiIn->biClrUsed;
  1299.     lpbiOut->biBitCount    = lpbiIn->biBitCount ; 
  1300.     lpbiOut->biCompression = BI_RGB;
  1301.     lpbiOut->biSizeImage   = wBytesPerPixel*(DWORD)dy*(DWORD)((dx+3)&~3);
  1302.  
  1303.     dx = (int)lpbiIn->biWidth;
  1304.     dy = (int)lpbiIn->biHeight;
  1305.  
  1306.     wBytesPerPixel = (lpbiIn->biBitCount+7)/8 ;
  1307.  
  1308.     hmemcpy(
  1309.         (LPBYTE)lpbiOut + (int)lpbiOut->biSize,
  1310.         (LPBYTE)lpbiIn  + (int)lpbiIn->biSize,
  1311.         (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  1312.  
  1313.     return ICERR_OK;
  1314. }
  1315.  
  1316. /*****************************************************************************
  1317.  *
  1318.  * DecompressGetPalette() implements ICM_GET_PALETTE
  1319.  *
  1320.  * This function has no Compress...() equivalent
  1321.  *
  1322.  * It is used to pull the palette from a frame in order to possibly do
  1323.  * a palette change.
  1324.  * 
  1325.  ****************************************************************************/
  1326. LRESULT NEAR PASCAL DecompressGetPalette(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
  1327. {
  1328.     DWORD dw;
  1329.  
  1330.     DPF("DecompressGetPalette()");
  1331.  
  1332.     if (dw = DecompressQueryFmt(pinst, lpbiIn))
  1333.         return dw;
  1334.  
  1335.     if (lpbiOut->biBitCount != 8) {
  1336.         return ICERR_BADFORMAT;
  1337.     }
  1338.  
  1339.     //
  1340.     // if you decompress full-color to 8 bit you need to put the "dither"
  1341.     // palette in lpbiOut
  1342.     //
  1343.     if (lpbiIn->biBitCount != 8) {
  1344.         return ICERR_BADFORMAT;
  1345.     }
  1346.     if (lpbiIn->biClrUsed == 0)
  1347.         lpbiIn->biClrUsed = 256;
  1348.  
  1349.     //
  1350.     // return the 8bit palette used for decompression.  
  1351.     //
  1352.     lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
  1353.     hmemcpy(
  1354.         (LPBYTE)lpbiOut + (int)lpbiOut->biSize,
  1355.         (LPBYTE)lpbiIn + (int)lpbiIn->biSize,
  1356.         (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
  1357.  
  1358.     lpbiOut->biClrUsed = lpbiIn->biClrUsed;
  1359.  
  1360.     return ICERR_OK;
  1361. }
  1362.  
  1363. /*****************************************************************************
  1364.  *
  1365.  * DecompressBegin() implements ICM_DECOMPRESS_BEGIN
  1366.  *
  1367.  * See CompressBegin()
  1368.  * 
  1369.  ****************************************************************************/
  1370. LRESULT NEAR PASCAL DecompressBegin(
  1371.     INSTINFO * pinst,
  1372.     DWORD dwFlags,
  1373.     LPBITMAPINFOHEADER lpbiSrc,
  1374.     LPVOID pSrc,
  1375.     int xSrc,
  1376.     int ySrc,
  1377.     int dxSrc,
  1378.     int dySrc,
  1379.     LPBITMAPINFOHEADER lpbiDst,
  1380.     LPVOID pDst,
  1381.     int xDst,
  1382.     int yDst,
  1383.     int dxDst,
  1384.     int dyDst)
  1385. {
  1386.     LONG l;
  1387.  
  1388.     if (l = DecompressQuery(pinst, dwFlags, lpbiSrc, pSrc, xSrc, ySrc, dxSrc, dySrc, lpbiDst, pDst, xDst, yDst, dxDst, dyDst))
  1389.         return l;
  1390.  
  1391.     //
  1392.     //  make sure biSizeImage is set, the decompress code needs it to be
  1393.     //
  1394.     if (lpbiDst->biSizeImage == 0)
  1395.         lpbiDst->biSizeImage = (DWORD)(WORD)abs((int)lpbiDst->biHeight)*(DWORD)(WORD)DIBWIDTHBYTES(*lpbiDst);
  1396.  
  1397.     pinst->fDecompress = TRUE;
  1398.  
  1399.     return ICERR_OK;
  1400. }
  1401.  
  1402. /*****************************************************************************
  1403.  *
  1404.  * Decompress() implements ICM_DECOMPRESS
  1405.  *
  1406.  * See DecompressBegin()
  1407.  * 
  1408.  ****************************************************************************/
  1409. LRESULT NEAR PASCAL Decompress(
  1410.     INSTINFO * pinst,
  1411.     DWORD dwFlags,
  1412.     LPBITMAPINFOHEADER lpbiSrc,
  1413.     LPVOID lpSrc,
  1414.     int xSrc,
  1415.     int ySrc,
  1416.     int dxSrc,
  1417.     int dySrc,
  1418.     LPBITMAPINFOHEADER lpbiDst,
  1419.     LPVOID lpDst,
  1420.     int xDst,
  1421.     int yDst,
  1422.     int dxDst,
  1423.     int dyDst)
  1424. {
  1425.     BOOL    fBegin;
  1426.  
  1427.     //
  1428.     //  if we are called without a begin do the begin now, but dont make
  1429.     //  the begin "stick"
  1430.     //
  1431.     if (!(fBegin = pinst->fDecompress))
  1432.     {
  1433.         LRESULT l;
  1434.  
  1435.         if (l = DecompressBegin(pinst, dwFlags, lpbiSrc, lpSrc, xSrc, ySrc, dxSrc, dySrc, lpbiDst, lpDst, xDst, yDst, dxDst, dyDst))
  1436.             return l;
  1437.  
  1438.     }
  1439.  
  1440.     //
  1441.     //  because 'SAMP' frames are key frames we dont need to do any thing if
  1442.     //  behind.
  1443.     //
  1444.     if (dwFlags & ICDECOMPRESS_HURRYUP)
  1445.         return ICERR_OK;
  1446.  
  1447.     /* do the decompression */
  1448.     switch(lpbiSrc->biBitCount)
  1449.     {
  1450.         case 8 :
  1451.             MyDecompress8(pinst,lpbiSrc, lpSrc, lpbiDst, lpDst, xDst, yDst);
  1452.             break ;
  1453.  
  1454.         case 16 :
  1455.             MyDecompress16(pinst,lpbiSrc, lpSrc, lpbiDst, lpDst, xDst, yDst);
  1456.             break ;
  1457.  
  1458.         case 24 :
  1459.             MyDecompress24(pinst,lpbiSrc, lpSrc, lpbiDst, lpDst, xDst, yDst);
  1460.             break ;
  1461.  
  1462.     }
  1463.  
  1464.     if (!fBegin)
  1465.     DecompressEnd(pinst);
  1466.  
  1467.     return ICERR_OK;
  1468. }
  1469.  
  1470. /*****************************************************************************
  1471.  *
  1472.  * DecompressEnd() implements ICM_DECOMPRESS_END
  1473.  *
  1474.  * See CompressEnd()
  1475.  *
  1476.  ****************************************************************************/
  1477. LRESULT NEAR PASCAL DecompressEnd(INSTINFO * pinst)
  1478. {
  1479.     DPF("DecompressEnd()");
  1480.  
  1481.     if (!pinst->fDecompress)
  1482.         return ICERR_ERROR;
  1483.  
  1484.     //
  1485.     //  clean up decompress stuff.
  1486.     //
  1487.  
  1488.     pinst->fDecompress = FALSE;
  1489.     return ICERR_OK;
  1490. }
  1491.  
  1492. /*****************************************************************************
  1493.  *
  1494.  * DrawQuery() implements ICM_DRAW_QUERY
  1495.  *
  1496.  ****************************************************************************/
  1497. BOOL NEAR PASCAL DrawQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiInput)
  1498. {
  1499.     return FALSE;
  1500. }
  1501.  
  1502. /*****************************************************************************
  1503.  *
  1504.  * DrawBegin() implements ICM_DRAW_BEGIN
  1505.  *
  1506.  * This is just like DecompressBegin() except that we also must prepare to
  1507.  * actually draw the bitmap on the screen. ICDRAWBEGIN provides info specific
  1508.  * to this task.
  1509.  *
  1510.  ****************************************************************************/
  1511. LRESULT NEAR PASCAL DrawBegin(INSTINFO * pinst,ICDRAWBEGIN FAR *icinfo, DWORD dwSize)
  1512. {
  1513.     DPF("DrawBegin()");
  1514.  
  1515.     if (1)  // we dont draw!
  1516.         return ICERR_UNSUPPORTED;
  1517.  
  1518.     if (pinst->fDrawBegun)
  1519.         return ICERR_OK;
  1520.  
  1521.     pinst->fDrawBegun = TRUE;
  1522.     
  1523.     //
  1524.     // but if we did draw we would get ready to draw here
  1525.     //
  1526.  
  1527.     return ICERR_OK;
  1528. }
  1529.  
  1530. /*****************************************************************************
  1531.  *
  1532.  * Draw implements ICM_DRAW
  1533.  *
  1534.  * Decompress and draw
  1535.  *
  1536.  ****************************************************************************/
  1537. LRESULT NEAR PASCAL Draw(INSTINFO * pinst, ICDRAW FAR *icinfo, DWORD dwSize)
  1538. {
  1539.     DPF("Draw()");
  1540.  
  1541.     if (!pinst->fDrawBegun)
  1542.         return ICERR_ERROR;
  1543.  
  1544.     return ICERR_UNSUPPORTED;
  1545. }
  1546.  
  1547. /*****************************************************************************
  1548.  *
  1549.  * DrawEnd() implements ICM_DRAW_END
  1550.  *
  1551.  * See DecompressEnd()
  1552.  *
  1553.  ****************************************************************************/
  1554. LRESULT NEAR PASCAL DrawEnd(INSTINFO * pinst)
  1555. {
  1556.     DPF("DrawEnd()");
  1557.  
  1558.     if (1)  // we dont draw!
  1559.         return ICERR_UNSUPPORTED;
  1560.  
  1561.     if (!pinst->fDrawBegun)
  1562.         return ICERR_ERROR;
  1563.  
  1564.     pinst->fDrawBegun = FALSE;
  1565.  
  1566.     //
  1567.     // but if we did we would clean up here
  1568.     //
  1569.  
  1570.     return ICERR_OK;
  1571. }
  1572.  
  1573. /*****************************************************************************
  1574.  *
  1575.  * ConfigureDlgProc() is called by Configure
  1576.  *
  1577.  * This is a standard dialog proc which allows the user to
  1578.  * pick config options for the driver.
  1579.  *
  1580.  ****************************************************************************/
  1581. BOOL FAR PASCAL _loadds ConfigureDlgProc(HWND hdlg, short msg, WORD wParam, LONG lParam)
  1582. {
  1583.     int             id;
  1584.     static int      s1;
  1585.     static int      s2;
  1586.     HWND            hsb;
  1587.     char            ach[10];
  1588.     
  1589.     static INSTINFO *pinst;
  1590.  
  1591.     #define SCROLL_MIN  1       
  1592.     #define SCROLL_MAX  16      
  1593.  
  1594.     #define SCROLL2_MIN  0       
  1595.     #define SCROLL2_MAX  4      
  1596.  
  1597.         
  1598.     switch (msg)
  1599.     {
  1600.         case WM_COMMAND:
  1601.             switch (wParam)
  1602.             {
  1603.                 case IDOK:
  1604.                     hsb = GetDlgItem(hdlg,ID_SCROLL);
  1605.                     pinst->CurrentState.dInfo.wPixelKeepRatio = s1 ;
  1606.                     hsb = GetDlgItem(hdlg,ID_SCROLL2);
  1607.                     pinst->CurrentState.dInfo.wColorBitsToDrop = s2 ;
  1608.                     EndDialog(hdlg,TRUE);
  1609.                     break;
  1610.  
  1611.                 case IDCANCEL:
  1612.                     EndDialog(hdlg,FALSE);
  1613.                     break;
  1614.             }
  1615.             break;
  1616.  
  1617.         case WM_HSCROLL:
  1618.             hsb = (HWND)HIWORD(lParam);
  1619.             id = GetWindowWord(hsb,GWW_ID);
  1620.  
  1621.             switch( id )
  1622.             {
  1623.                 case ID_SCROLL:
  1624.                     s1 = GetScrollPos(hsb,SB_CTL);
  1625.  
  1626.                     switch (wParam)
  1627.                     {
  1628.                         case SB_LINEDOWN:      s1 += 1; break;
  1629.                         case SB_LINEUP:        s1 -= 1; break;
  1630.                         case SB_PAGEDOWN:      s1 += 4; break;
  1631.                         case SB_PAGEUP:        s1 -= 4; break;
  1632.                         case SB_THUMBTRACK:
  1633.                         case SB_THUMBPOSITION: s1 = (int)LOWORD(lParam); break;
  1634.                         default:               return TRUE;
  1635.                     }           
  1636.                 
  1637.                     s1 = max(SCROLL_MIN,min(SCROLL_MAX,s1));
  1638.                     SetScrollPos(hsb,SB_CTL,s1,TRUE);
  1639.                     wsprintf(ach, "%02d", s1);
  1640.                     SetDlgItemText(hdlg,ID_TEXT,ach);
  1641.                     return TRUE;
  1642.  
  1643.                 case ID_SCROLL2:
  1644.                     s2 = GetScrollPos(hsb,SB_CTL);
  1645.  
  1646.                     switch (wParam)
  1647.                     {
  1648.                         case SB_LINEDOWN:      s2 += 1; break;
  1649.                         case SB_LINEUP:        s2 -= 1; break;
  1650.                         case SB_PAGEDOWN:      s2 += 4; break;
  1651.                         case SB_PAGEUP:        s2 -= 4; break;
  1652.                         case SB_THUMBTRACK:
  1653.                         case SB_THUMBPOSITION: s2 = (int)LOWORD(lParam); break;
  1654.                         default:               return TRUE;
  1655.                     }           
  1656.  
  1657.                     s2 = max(SCROLL2_MIN,min(SCROLL2_MAX,s2));
  1658.                     SetScrollPos(hsb,SB_CTL,s2,TRUE);
  1659.                     wsprintf(ach, "%02d", s2);
  1660.                     SetDlgItemText(hdlg,ID_TEXT2,ach);
  1661.                     return TRUE;
  1662.  
  1663.             }
  1664.             return TRUE ;
  1665.  
  1666.  
  1667.         case WM_INITDIALOG:
  1668.             pinst = (INSTINFO *)lParam;
  1669.  
  1670.             hsb = GetDlgItem(hdlg,ID_SCROLL);
  1671.             s1 = pinst->CurrentState.dInfo.wPixelKeepRatio;
  1672.             SetScrollRange(hsb,SB_CTL,SCROLL_MIN, SCROLL_MAX, TRUE);
  1673.             SetScrollPos(hsb,SB_CTL,s1,TRUE);
  1674.             wsprintf(ach, "%02d", s1);
  1675.             SetDlgItemText(hdlg,ID_TEXT,ach);
  1676.  
  1677.             hsb = GetDlgItem(hdlg,ID_SCROLL2);
  1678.             s2 = pinst->CurrentState.dInfo.wColorBitsToDrop;
  1679.             SetScrollRange(hsb,SB_CTL,SCROLL2_MIN, SCROLL2_MAX, TRUE);
  1680.             SetScrollPos(hsb,SB_CTL,s2,TRUE);
  1681.             wsprintf(ach, "%02d", s2);
  1682.             SetDlgItemText(hdlg,ID_TEXT2,ach);
  1683.  
  1684.             return TRUE;
  1685.     }
  1686.     return FALSE;
  1687. }
  1688.  
  1689. /*****************************************************************************
  1690.  *
  1691.  * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  1692.  *
  1693.  * The messages will be send to COM1: like any debug message. To 
  1694.  * enable debug output, add the following to WIN.INI :
  1695.  *
  1696.  * [debug]
  1697.  * ICSAMPLE=1
  1698.  *
  1699.  ****************************************************************************/
  1700.  
  1701. #ifdef DEBUG
  1702.  
  1703. void FAR cdecl dprintf(LPSTR szFormat, ...)
  1704. {
  1705.     char ach[128];
  1706.  
  1707.     static BOOL fDebug = -1;
  1708.  
  1709.     if (fDebug == -1)
  1710.         fDebug = GetProfileInt("Debug", MODNAME, FALSE);
  1711.  
  1712.     if (!fDebug)
  1713.         return;
  1714.  
  1715.     lstrcpy(ach, MODNAME ": ");
  1716.     wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
  1717.     lstrcat(ach, "\r\n");
  1718.  
  1719.     OutputDebugString(ach);
  1720. }
  1721.  
  1722. #endif
  1723.